package JVM.第02篇_类的加载篇;

import org.junit.Test;

import java.io.Serializable;
import java.util.Random;

/**
 * 主动使用的情况
 * Class只有在必须要首次使用的时候才会被装载，Java虚 拟机不会无条件地装载Class类型
 * 。Java虚拟机规定，一个类或接口在初次使用前，必须要进行初始化。
 * 这里指的“使用”，是指主动使用。
 * 主动使用只有下列几种情况:
 *      (即:如果出现如下的情况，则会对类进行初始化操作。
 *      而初始化操作之前的加载、验证、准备已经完成。)
 * 1.当创建一个类的实例时，比如使用new关键字，或者通过反射、克隆、反序列化。
 * 2.当调用类的静态方法时，即当使用了字节码invokestatic指令。
 * 3.当使用类、接口的静态字段时(final修饰特殊考虑)，
 *   比如，使用get static或者put static指令。
 * 4.当使用java.lang.reflect包中的方法反射类的方法时。比如:
 *      Class.forName(”com.atguigu.java.Test")
 * 5.当初始化子类时，如果发现其父类还没有进行过初始化，则需要先触发其父类的初始化
 * 6.如果一个接口定义了default方法， 那么直接实现或者间接实现该接口的类的初始化，
 *   该接口要在其之前被初始化。
 * 7.当虚拟机启动时，用户需要指定一个要执行的主类(包含main()方法的那个类)，
 *   虚拟机会先初始化这个主类。
 *
 * 被动使用的情况
 * 除了以上的情况属于主动使用，其他的情况均属于被动使用。
 * 被动使用不会引起类的初始化也就是说:
 *      并不是在代码中出现的类，就一定会被加载或者初始化。
 *      如果不符合主动使用的条件，类就不会初始化。
 * 1. 当访问一个静态字段时，只有真正声明这个字段的类才会被初始化。
 *      当通过子类引用父类的静态变量，不会导致子类初始化
 * 2.通过数组定义类引用，不会触发此类的初始化
 * 3.引用常量不会触发此类或接口的初始化。因为常量在链接阶段就已经被显式赋值了。
 * 4.调用ClassLoader类的loadClass()方法加载一个类，并不是对类的主动使用，
 *      不会导致类的初始化。
 *
 * >被动的使用，意味着不需要执行初始化环节，意味着没有<clinit>()的调用。
 *
 * Class的forName("Java.lang.String")和
 * Class的getClassLoader( )的loadClass("Java.lang String")有什么区别?
 *
 *  forName("Java.lang.String"): 会初始化
 * Class的getClassLoader( )的loadClass("Java.lang String")：只会进行装载
 */
public class A5_类的初始化情况 {
    @Test
    public void test1(){
        System.out.println(A.I);
    }
    @Test
    public void test2(){
        System.out.println(A.J);
    }
    @Test
    public void test3(){
        new A().method1();
    }
}
class A implements Serializable ,B{
    //在 类的装载 中加载
    static final int I = 10;//不输出  初始化

    //输出  初始化   因为 使用了 new Random() ,使其在初始化时加载
    static final int J = new Random().nextInt(10);
    static {
        System.out.println("初始化");
    }
}
interface B{
    public static final Thread t = new Thread();
    public default void method1(){
        System.out.println("default");
    }
}
